import asyncio
from bleak import BleakScanner
from bleak.backends.scanner import AdvertisementData
from bleak.backends.device import BLEDevice

# 蓝牙广播数据类型定义（参考蓝牙核心规范）
AD_TYPE_FLAGS = 0x01
AD_TYPE_COMPLETE_LOCAL_NAME = 0x09
AD_TYPE_SHORT_LOCAL_NAME = 0x08
AD_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF
AD_TYPE_SERVICE_UUIDS_16BIT_COMPLETE = 0x03
AD_TYPE_SERVICE_UUIDS_16BIT_INCOMPLETE = 0x02
AD_TYPE_TX_POWER_LEVEL = 0x0A


def parse_advertisement_data(raw_data: bytes) -> dict:
    """
    解析原始广播数据（符合蓝牙GAP规范的AD结构）
    参考：https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/
    """
    parsed = {
        "flags": None,
        "complete_local_name": None,
        "short_local_name": None,
        "manufacturer_data": None,
        "service_uuids_16bit": [],
        "tx_power_level": None,
        "raw": raw_data.hex()  # 原始十六进制数据
    }

    index = 0
    while index < len(raw_data):
        # 每个AD结构格式：[长度(1字节)][类型(1字节)][数据(n字节)]
        length = raw_data[index]
        if length == 0:
            break  # 无效结构，终止解析
        index += 1

        ad_type = raw_data[index]
        ad_data = raw_data[index + 1: index + 1 + length - 1]  # 长度包含类型字段，所以减1
        index += length

        # 解析不同类型的AD数据
        if ad_type == AD_TYPE_FLAGS:
            parsed["flags"] = ad_data.hex()
        elif ad_type == AD_TYPE_COMPLETE_LOCAL_NAME:
            parsed["complete_local_name"] = ad_data.decode("utf-8", errors="replace")
        elif ad_type == AD_TYPE_SHORT_LOCAL_NAME:
            parsed["short_local_name"] = ad_data.decode("utf-8", errors="replace")
        elif ad_type == AD_TYPE_MANUFACTURER_SPECIFIC_DATA:
            # 厂商数据格式：[公司ID(2字节)][自定义数据(n字节)]
            if len(ad_data) >= 2:
                company_id = int.from_bytes(ad_data[:2], byteorder="little")
                company_data = ad_data[2:].hex()
                parsed["manufacturer_data"] = {
                    "company_id": company_id,
                    "company_id_hex": ad_data[:2].hex(),
                    "data": company_data
                }
        elif ad_type in [AD_TYPE_SERVICE_UUIDS_16BIT_COMPLETE, AD_TYPE_SERVICE_UUIDS_16BIT_INCOMPLETE]:
            # 16位UUID（每2字节一个UUID）
            for i in range(0, len(ad_data), 2):
                uuid = int.from_bytes(ad_data[i:i + 2], byteorder="little")
                parsed["service_uuids_16bit"].append(f"0x{uuid:04x}")
        elif ad_type == AD_TYPE_TX_POWER_LEVEL:
            # 发射功率（范围：-127 ~ +127 dBm）
            parsed["tx_power_level"] = int.from_bytes(ad_data, byteorder="little", signed=True)

    return parsed


async def scan_ble_devices(timeout: int = 10):
    """扫描周围的BLE设备并返回解析后的广播数据"""
    print(f"开始扫描BLE设备（{timeout}秒后结束）...")

    # 扫描回调：处理发现的设备
    def detection_callback(device: BLEDevice, advertisement_data: AdvertisementData):
        # 解析广播数据
        parsed_data = parse_advertisement_data(advertisement_data.manufacturer_data.get(0x0000, b"") +
                                               advertisement_data.service_data.get(0x0000, b""))
        # 补充设备基本信息
        device_info = {
            "address": device.address,
            "name": device.name or "未知设备",
            "rssi": advertisement_data.rssi,  # 信号强度（dBm）
            "advertisement": parsed_data
        }

        # 打印设备信息（实际使用中可存储到列表）
        print("\n" + "=" * 50)
        print(f"设备地址: {device_info['address']}")
        print(f"设备名称: {device_info['name']}")
        print(f"信号强度: {device_info['rssi']} dBm")
        print("广播数据解析:")
        for key, value in device_info["advertisement"].items():
            if value is not None and key != "raw":
                print(f"  {key}: {value}")
        print(f"原始广播数据: {advertisement_data}")

    # 启动扫描
    scanner = BleakScanner(detection_callback=detection_callback)
    await scanner.start()
    await asyncio.sleep(timeout)
    await scanner.stop()

    print("\n扫描结束")


if __name__ == "__main__":
    # 运行扫描（需要Windows 10+，且蓝牙已启用）
    asyncio.run(scan_ble_devices(timeout=3))
